package com.urbane.generator.controller;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.urbane.generator.model.dto.GenerateRequest;
import com.urbane.generator.model.vo.ResponseResult;
import com.urbane.generator.service.CodeGeneratorService;
import com.urbane.generator.service.GenDataSourceService;
import com.urbane.generator.service.GenTemplateService;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * 代码生成控制器
 * <p>提供前端界面触发代码生成的核心 API 接口</p>
 * <p>接收前端配置，执行生成，返回 ZIP 文件下载路径</p>
 *
 * @author your-name
 * @date 2024-07-06
 */
// 参考，接口添加作者 https://doc.xiaominfo.com/docs/features/author
// 有时候在开发接口时,我们希望给该接口添加一个作者,这样前端或者别个团队来对接该接口时,
// 如果该接口返回的数据或者调用有问题,都能准确找到该人,提升效率. 类 @ApiSupport   方法 @ApiOperationSupport
@ApiSupport(author = "xiaoymin@foxmail.com", order = 284)
@RestController
@RequestMapping("/api/codegen")
@RequiredArgsConstructor
public class CodeGenController {

    private final GenDataSourceService genDataSourceService;
    private final GenTemplateService genTemplateService;
    private final CodeGeneratorService codeGeneratorService; // 核心生成引擎

    /**
     * 执行代码生成
     *
     * @param request 生成请求参数（包含数据源ID、表名列表、模板映射、作者）
     * @return 生成结果（成功则返回 ZIP 文件名）
     * &#064;api  {POST} /api/codegen/generate 执行代码生成
     * &#064;apiName  GenerateCode
     * &#064;apiGroup  代码生成
     * &#064;apiParamExample  {json} 请求示例:
     *     {
     *       "dataSourceId": 1,
     *       "tableNames": ["t_user", "t_product"],
     *       "templateMap": {
     *         "vue-list": "vue-list.vue.ftl",
     *         "ts-api": "api.ts.ftl",
     *         "ts-types": "types.ts.ftl"
     *       },
     *       "author": "张三"
     *     }
     * &#064;apiSuccessExample  {json} 成功响应:
     *     HTTP/1.1 200 OK
     *     {
     *       "success": true,
     *       "message": "生成成功",
     *       "zipFileName": "codegen_1712345678.zip"
     *     }
     * &#064;apiErrorExample  {json} 失败响应:
     *     HTTP/1.1 500 Internal Server Error
     *     {
     *       "success": false,
     *       "message": "生成失败：数据库连接失败"
     *     }
     */
    @PostMapping("/generate")
    @ApiOperationSupport(author = "xiaoymin@foxmail.com")
    @Operation(summary = "执行代码生成", description = "根据前端配置，动态生成后端 Java 代码和前端 Vue/TS 代码，并打包为 ZIP")
    public ResponseResult<Map<String, Object>> generateCode(@Valid @RequestBody GenerateRequest request) {
        try {
            String zipFileName = codeGeneratorService.generateCode(request);

            // 保存生成历史记录
            GenHistory history = new GenHistory();
            history.setDataSourceId(request.getDataSourceId());
            history.setTableNames(new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(request.getTableNames()));
            history.setTemplateSet(new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(request.getTemplateMap()));
            history.setGeneratedBy(request.getAuthor());
            history.setFilePath("/downloads/" + zipFileName);
            history.setStatus("SUCCESS");

            // 保存到数据库（可选，用于审计）
            // genHistoryMapper.insert(history);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("message", "生成成功");
            response.put("zipFileName", zipFileName);

            return ResponseEntity.ok(response);
        } catch (Exception e) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", false);
            response.put("message", "生成失败：" + e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 下载生成的 ZIP 文件
     *
     * @param zipFileName ZIP 文件名
     * @return ZIP 文件流
     * @api {GET} /api/codegen/download/{zipFileName} 下载生成的代码包
     * @apiName DownloadGeneratedCode
     * @apiGroup 代码生成
     * @apiParam {String} zipFileName ZIP 文件名（必须）
     * @apiParamExample {url} 请求示例:
     *     /api/codegen/download/codegen_1712345678.zip
     */
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "更新成功",
                    content = @Content(schema = @Schema(implementation = Result.class))
            ),
            @ApiResponse(
                    responseCode = "400",
                    description = "参数校验失败",
                    content = @Content(schema = @Schema(implementation = Result.class))
            ),
            @ApiResponse(
                    responseCode = "404",
                    description = "用户不存在",
                    content = @Content(schema = @Schema(implementation = Result.class))
            ),
            @ApiResponse(
                    responseCode = "500",
                    description = "系统内部错误",
                    content = @Content(schema = @Schema(implementation = Result.class))
            )
    })
    @GetMapping("/download/{zipFileName}")
    @Operation(summary = "代码预览", description = "根据文件名下载由代码生成器生成的 ZIP 压缩包")
    public ResponseResult<FileSystemResource> previewCode(@PathVariable String zipFileName) {
        String filePath = "temp-gen/" + zipFileName;
        File file = new File(filePath);
        if (!file.exists()) {
            return ResponseEntity.notFound().build();
        }

        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "attachment; filename=" + zipFileName);
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");

        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(file.length())
                .contentType(org.springframework.http.MediaType.APPLICATION_OCTET_STREAM)
                .body(new FileSystemResource(file));
    }
}